# uncompyle6 version 3.2.3
# Python bytecode 3.6 (3379)
# Decompiled from: Python 3.6.8 |Anaconda custom (64-bit)| (default, Feb 21 2019, 18:30:04) [MSC v.1916 64 bit (AMD64)]
# Embedded file name: helpers\encryption\file_aes_cbc.py
__author__ = "Attila Gerendi (Sanyi)"
from Crypto.Cipher import AES
from Crypto.Random import get_random_bytes
from helpers.encryption.exceptions import InvalidKey, InvalidData, WrongHeader
from helpers.encryption.openssl import openssl_kdf


def encrypt_file(
    in_filename, out_filename, secret, chunk_size=8192, default_encoding="utf-8"
):
    if not chunk_size % 16 == 0:
        raise AssertionError
    salt = get_random_bytes(8)
    if isinstance(secret, str):
        secret = secret.encode(default_encoding)
    mat = (b"").join([x for x in openssl_kdf(48, secret, salt)])
    key = mat[0:32]
    iv = mat[32:48]
    aes = AES.new(key, AES.MODE_CBC, iv)
    with open(in_filename, "rb") as (infile):
        with open(out_filename, "wb") as (outfile):
            outfile.write(b"Salted__")
            outfile.write(salt)
            while True:
                chunk = infile.read(chunk_size)
                chunk_length = len(chunk)
                if chunk_length == 0:
                    padding_length = 16
                    padding = bytes((padding_length,) * padding_length)
                    outfile.write(aes.encrypt(padding))
                    break
                elif chunk_length % 16 != 0:
                    padding_length = 16 - chunk_length % 16
                    padding = bytes((padding_length,) * padding_length)
                    outfile.write(aes.encrypt(chunk + padding))
                    break
                else:
                    outfile.write(aes.encrypt(chunk))


def decrypt_file(
    in_filename, out_filename, secret, chunk_size=8192, default_encoding="utf-8"
):
    if isinstance(secret, str):
        secret = secret.encode(default_encoding)
    with open(in_filename, "rb") as (infile):
        header = infile.read(16)
        if len(header) != 16:
            raise InvalidData()
        if header[0:8] != b"Salted__":
            raise WrongHeader()
        salt = header[8:16]
        mat = (b"").join([x for x in openssl_kdf(48, secret, salt)])
        key = mat[0:32]
        iv = mat[32:48]
        aes = AES.new(key, AES.MODE_CBC, iv)
        chunk = None
        s = 0
        with open(out_filename, "wb") as (outfile):
            while True:
                d = infile.read(chunk_size)
                l = len(d)
                s += l
                if l == 0:
                    if not chunk or len(chunk) < 16:
                        raise InvalidData()
                    padding_length = chunk[-1]
                    if (
                        bytes((padding_length,) * padding_length)
                        != chunk[-padding_length:]
                    ):
                        raise InvalidKey()
                    outfile.truncate(s - padding_length)
                    return
                chunk = aes.decrypt(d)
                outfile.write(chunk)


def decrypt_file_generator(
    in_filename, secret, chunk_size=8192, default_encoding="utf-8"
):
    if isinstance(secret, str):
        secret = secret.encode(default_encoding)
    with open(in_filename, "rb") as (infile):
        header = infile.read(16)
        if len(header) != 16:
            raise InvalidData()
        if header[0:8] != b"Salted__":
            raise WrongHeader()
        salt = header[8:16]
        mat = (b"").join([x for x in openssl_kdf(48, secret, salt)])
        key = mat[0:32]
        iv = mat[32:48]
        aes = AES.new(key, AES.MODE_CBC, iv)
        data = infile.read(chunk_size)
        if len(data) == 0:
            return
        while True:
            chunk = aes.decrypt(data)
            data = infile.read(chunk_size)
            l = len(data)
            if l == 0:
                if not chunk or len(chunk) < 16:
                    raise InvalidData()
                padding_length = chunk[-1]
                if bytes((padding_length,) * padding_length) != chunk[-padding_length:]:
                    raise InvalidKey()
                yield chunk[:-padding_length]
                return
            yield chunk
